package com.qjl.parser.logicflow;

import com.qjl.core.ELNode;
import com.qjl.core.ExpressLanguageParseException;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.util.CollectionUtils;

import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

@Data
@AllArgsConstructor
@NoArgsConstructor
public class LogicFlowManager {
	/**
	 * 待解析的LogicFlow数据
	 */
	private LogicFlow logicFlow;


	/**
	 * 提取Lf节点的根节点id
	 *
	 * @return {@link String}
	 */
	public String getRootId() {

		//获取初始化节点
		Set<String> targetNodeIds = this.logicFlow.getEdges().stream().map(LfEdge::getTargetNodeId).collect(Collectors.toSet());
		Set<String> sourceNodeIds = this.logicFlow.getEdges().stream().map(LfEdge::getSourceNodeId).collect(Collectors.toSet());
		if (sourceNodeIds.size() - targetNodeIds.size() > 1) {
			throw new ExpressLanguageParseException("只能有一个开始节点");
		}
		for (String sourceNodeId : sourceNodeIds) {
			if (!targetNodeIds.contains(sourceNodeId)) {
				return sourceNodeId;
			}
		}
		return null;
	}

	public List<LfNode> getNodesByIds(List<String> ids){
		if( CollectionUtils.isEmpty(ids) || CollectionUtils.isEmpty(this.logicFlow.getNodes())){
			return new ArrayList<>();
		}

		return this.logicFlow.getNodes().stream().filter(e->ids.contains(e.getId())).collect(Collectors.toList());

	}

	public List<LfNode> getNodes() {
		return this.logicFlow.getNodes();
	}


	public List<LfEdge> getEdges() {
		return this.logicFlow.getEdges();
	}

	public Map<String, LfNode> getAllWhenNodeMap() {
		Map<String, LfNode> whenNodeMap = this.getNodes().stream()
				.filter(e -> ELNode.ELNameEnum.WHEN.name().equals(e.getProperties().get(LfNodePropertyEnum.nodeType.name())))
				.collect(Collectors.toMap(LfNode::getId, Function.identity(), (a, b) -> a));

		return whenNodeMap;
	}


	/**
	 * 获取最外层的when 节点
	 *
	 * @return
	 */
	public Set<LfNode> getOutermostLayerWhen() {
		//获取when节点Map
		//nodeId -> LfNode
		Map<String, LfNode> whenNodeMap = this.getAllWhenNodeMap();

		if (CollectionUtils.isEmpty(whenNodeMap)) {
			return Collections.emptySet();
		}

		Collection<LfNode> whens = whenNodeMap.values();
		if (CollectionUtils.isEmpty(whens)) {
			return Collections.emptySet();
		}

		Set<String> allWhenChild = whens.stream()
				.map(LfNode::getChildren)
				.flatMap(List::stream)
				.collect(Collectors.toSet());

		return whens.stream().filter(e -> !allWhenChild.contains(e.getId())).collect(Collectors.toSet());
	}


	/**
	 * 找when的外部的第一个节点
	 *
	 * @param enterWhenSourceId    当输入源id
	 * @param whenChildIds         when中所有孩子节点
	 * @return {@link String}
	 */
	public String doFindOutSideWhenNode(String enterWhenSourceId,
										 Map<String, List<LfEdge>> sourceNodeToEdgesMap,
										 Set<String> whenChildIds) {
		List<LfEdge> edgeEntities = this.getReachableEdge(enterWhenSourceId, sourceNodeToEdgesMap);
		//没边
		if (CollectionUtils.isEmpty(edgeEntities)) {
			return null;
		}
		for (LfEdge edge : edgeEntities) {
			String targetNodeId = edge.getTargetNodeId();
			//不在框框中，就返回
			if (!whenChildIds.contains(targetNodeId)) {
				return targetNodeId;
			} else {
				String s = this.doFindOutSideWhenNode(targetNodeId,sourceNodeToEdgesMap,  whenChildIds);
				if (s != null) {
					return s;
				}
			}
		}
		return null;
	}

	/**
	 * 判断是否有且只有一个子节点
	 *
	 * @param currentId
	 * @param sourceNodeToEdgesMap
	 * @return
	 */
	public Boolean hasOnlyOneNext(String currentId, Map<String, List<LfEdge>> sourceNodeToEdgesMap) {
		if(!this.hasNext(currentId,sourceNodeToEdgesMap)){
			return false;
		}
		List<LfEdge> edgeEntities1 = this.getReachableEdge(currentId,sourceNodeToEdgesMap);
		return edgeEntities1.size()==1;
	}

	/**
	 * 判断是否有多个节点
	 * @param currentId
	 * @param sourceNodeToEdgesMap
	 * @return
	 */
	public Boolean hasManyNext(String currentId, Map<String, List<LfEdge>> sourceNodeToEdgesMap) {
		if(!this.hasNext(currentId,sourceNodeToEdgesMap)){
			return false;
		}
		List<LfEdge> edgeEntities1 = this.getReachableEdge(currentId,sourceNodeToEdgesMap);
		return edgeEntities1.size() > 1;
	}


	/**
	 * 判断是否有下一个子节点
	 *
	 * @param currentId
	 * @param sourceNodeToEdgesMap
	 * @return
	 */
	public boolean hasNext(String currentId, Map<String, List<LfEdge>> sourceNodeToEdgesMap) {
		if (CollectionUtils.isEmpty(sourceNodeToEdgesMap)) {
			return false;
		}

		boolean b = sourceNodeToEdgesMap.containsKey(currentId);
		if (!b) {
			return false;
		}
		List<LfEdge> reachableEdge = this.getReachableEdge(currentId,sourceNodeToEdgesMap);
		return !CollectionUtils.isEmpty(reachableEdge);
	}

	public List<LfEdge> getReachableEdge(String currentId, Map<String, List<LfEdge>> sourceNodeToEdgesMap){
		List<LfEdge> lfEdges = sourceNodeToEdgesMap.get(currentId);
		if(CollectionUtils.isEmpty(lfEdges)){
			return Collections.emptyList();
		}
		List<LfNode> nodes = logicFlow.getNodes();
		if(CollectionUtils.isEmpty(nodes)){
			return Collections.emptyList();
		}
		//能触达目标的才行
		List<String> nodeIds = nodes.stream().map(LfNode::getId).collect(Collectors.toList());
		return lfEdges.stream()
				.filter(e-> nodeIds.contains(e.getTargetNodeId()))
				.collect(Collectors.toList());
	}

	public String getNextFirstOne(String currentId, Map<String, List<LfEdge>> sourceNodeToEdgesMap) {
		List<LfEdge> edgeEntities1 = this.getReachableEdge(currentId,sourceNodeToEdgesMap);
		if (CollectionUtils.isEmpty(edgeEntities1)) {
			return null;
		}
		return edgeEntities1.get(0).getTargetNodeId();
	}
	public List<String> getNextAll(String currentId, Map<String, List<LfEdge>> sourceNodeToEdgesMap) {
		List<LfEdge> edgeEntities1 = this.getReachableEdge(currentId,sourceNodeToEdgesMap);
		if (CollectionUtils.isEmpty(edgeEntities1)) {
			return new ArrayList<>();
		}
		return edgeEntities1.stream().map(LfEdge::getTargetNodeId).collect(Collectors.toList());
	}


	/**
	 * 校验If 或Switch 组件, 如果IF组件中是否相反时调整一下
	 *
	 * @param propertyNodeType 属性节点类型
	 * @param edgeEntities     边缘实体
	 */
	public void validateIfOrSwitchNode(String propertyNodeType, List<LfEdge> edgeEntities) {
		if (CollectionUtils.isEmpty(edgeEntities)) {
			throw new ExpressLanguageParseException("判断组件IF或选择组件SWITCH的子节点必须大于等于1");
		}
		if (ELNode.ELNameEnum.IF.name().equals(propertyNodeType)) {
			if (edgeEntities.size() > 2) {
				throw new ExpressLanguageParseException("判断组件IF 的子节点必须小于等于2");
			}
			if (edgeEntities.size() == 1) {
				String txt = Optional.of(edgeEntities.get(0))
						.map(LfEdge::getText)
						.map(LfEdge.TextEntity::getValue)
						.orElse("");
				if (textIsFalse(txt)) {
					throw new ExpressLanguageParseException("判断组件IF 的只有一个子节点时，不能为 ‘否’ ");
				}
			}
			if (edgeEntities.size() == 2) {
				String aText = Optional.of(edgeEntities.get(0))
						.map(LfEdge::getText)
						.map(LfEdge.TextEntity::getValue)
						.orElse("");
				String bText = Optional.of(edgeEntities.get(1))
						.map(LfEdge::getText)
						.map(LfEdge.TextEntity::getValue)
						.orElse("");

				boolean b = (this.textIsTrue(aText) && this.textIsTrue(bText)) ||
						(this.textIsFalse(aText) && this.textIsFalse(bText));

				if (b) {
					throw new ExpressLanguageParseException("判断组件IF 的两个子节点，不能同时为 ‘是’ 或 ‘否’ ");
				}
				if (this.textIsTrue(bText) || this.textIsFalse(aText)) {
					// 交换两个元素的位置
					Collections.swap(edgeEntities, 0, 1);
				}
			}
		}
	}

	/**
	 * 判断文本是错误
	 *
	 * @param text 文本
	 * @return boolean
	 */
	private boolean textIsFalse(String text) {
		List<String> strings = Arrays.asList("否", "false", "False", "FALSE");
		return strings.contains(text);
	}

	/**
	 * 判断文本是正确
	 *
	 * @param text 文本
	 * @return boolean
	 */
	private boolean textIsTrue(String text) {
		List<String> strings = Arrays.asList("是", "true", "True", "TRUE");
		return strings.contains(text);
	}

}
